import * as cloud from 'wx-server-sdk';
import { PublishMessage, CreateDevice, DescribeDevice, DescribeDeviceShadow, CreateTask, DescribeTask } from 'api';

enum LedTaskExecutedStatus {
  Wait = 0,
  Success = 1,
  CreateTaskSuccess = 2,
}

const iconv = require("iconv-lite");

cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV as unknown as string
})
const db = cloud.database()
const _ = db.command



exports.main = async (_event: any, _context: any) => {
  const { eventCode, data, deviceName, ledTaskId, text } = _event
  console.log('run', eventCode);

  let rsp: any = null;
  try {
    check_deviceName(deviceName)
    switch (eventCode) {
      case "SendText":
        rsp = await onSendText(deviceName, data)
        break;
      case "CreateDevice":
        rsp = await onCreateDevice(deviceName)
        break;
      case "DescribeDevice":
        rsp = await onDescribeDevice(deviceName)
        break;
      case "DescribeDeviceShadow":
        rsp = await onDescribeDeviceShadow(deviceName)
        break;
      case "CreateLedTaskText":
        rsp = await onCreateLedTaskText(ledTaskId)
        break;
      case "DescribeTask":
        rsp = await onDescribeTask(ledTaskId)
        break;
      case "GbkBase64toUtf8":
        rsp = await onGbkBase64toUtf8(text)
        break;
      default:
        throw new Error("eventCode Error");
    }
    return {
      code: 0,
      msg: 'ok',
      data: rsp
    }
  } catch (error) {
    return {
      code: -1,
      msg: error.message
    }
  }
}


function check_deviceName(deviceName: string) {
  if (!deviceName) {
    throw new Error("deviceName 不能为空");
  }
}

async function onCreateDevice(deviceName: string) {
  const b = await getWeappConfig(['SecretId', 'SecretKey', 'ProductId'])
  const a = await CreateDevice(b.SecretId, b.SecretKey, {
    ProductId: b.ProductId,
    DeviceName: deviceName,
  })
  return a
}

async function onDescribeDeviceShadow(deviceName: string) {
  const b = await getWeappConfig(['SecretId', 'SecretKey', 'ProductId'])
  const a = await DescribeDeviceShadow(b.SecretId, b.SecretKey, {
    ProductId: b.ProductId,
    DeviceName: deviceName,
  })
  // 移除敏感信息
  return a
}


async function onDescribeDevice(deviceName: string) {
  const b = await getWeappConfig(['SecretId', 'SecretKey', 'ProductId'])
  const a = await DescribeDevice(b.SecretId, b.SecretKey, {
    ProductID: b.ProductId,
    DeviceName: deviceName,
  })
  // 移除敏感信息
  return {
    DeviceName: a['DeviceName'],
    Online: a['Online'],
    Version: a['Version'],
    LoginTime: a['LoginTime'],
    LastUpdateTime: a['LastUpdateTime']
  }
}

async function onCreateLedTaskText(ledTaskId: string) {
  if (!ledTaskId) throw new Error("ledTaskId 不能为空");
  const col = db.collection('LedTask')
  const d = await col.doc(ledTaskId).get() as cloud.DB.IQuerySingleResult
  const { executedStatus, deviceId, changeTime, ledtext, speed, count } = d.data
  if (executedStatus === LedTaskExecutedStatus.Wait) {
    const b = await getWeappConfig(['SecretId', 'SecretKey', 'ProductId'])
    const a = await CreateTask(b.SecretId, b.SecretKey, {
      TaskType: 'PublishMessage',
      ProductId: b.ProductId,
      /** 执行任务的设备名的正则表达式 */
      DeviceNameFilter: deviceId,
      /** 任务开始执行的时间。 取值为 Unix 时间戳，单位秒，且需大于等于当前时间时间戳，0为系统当前时间时间戳，即立即执行，最大为当前时间86400秒后，超过则取值为当前时间86400秒后 */
      ScheduleTimeInSeconds: parseInt(`${new Date(changeTime).getTime() / 1000}`),
      Tasks: {
        PublishMessageTask: {
          Topic: `text`,
          Payload: LedTextParams2Json(ledtext, speed, count)
        }
      },
    })
    console.log('创建任务', a);
    if (a.TaskId) {
      return await col.doc(ledTaskId).update({
        data: {
          executedStatus: LedTaskExecutedStatus.CreateTaskSuccess,
          taskId: a.TaskId
        }
      })
    }
    return a
  } else {
    throw new Error("executedStatus is not Wait")
  }
}

async function onDescribeTask(ledTaskId: string) {
  if (!ledTaskId) throw new Error("ledTaskId 不能为空");
  const col = db.collection('LedTask')
  const d = await col.doc(ledTaskId).get() as cloud.DB.IQuerySingleResult
  const { taskId } = d.data
  const b = await getWeappConfig(['SecretId', 'SecretKey', 'ProductId'])
  const a = await DescribeTask(b.SecretId, b.SecretKey, {
    Id: taskId
  })
  console.log("获取任务详情", a);

  return a
}


async function onSendText(deviceName: string, { text, speed, count }) {
  const topic = 'text'
  const qos = 0
  const Payload = LedTextParams2Json(text, speed, count)
  const b = await getWeappConfig(['SecretId', 'SecretKey', 'ProductId'])
  const a = await PublishMessage(b.SecretId, b.SecretKey, {
    Topic: `${b.ProductId}/${deviceName}/${topic}`,
    Payload: Payload,
    ProductId: b.ProductId,
    DeviceName: deviceName,
    Qos: qos,
  })
  return a
}

async function getWeappConfig(id: string[]) {
  const weapp_config = await db.collection('WeappConfig').where({
    _id: _.in(id)
  }).get() as cloud.DB.IQueryResult;
  const r = {
    SecretId: '',
    SecretKey: '',
    ProductId: '',
    DefinedPsk: ''
  }
  for (let i = 0; i < weapp_config.data.length; i++) {
    const e = weapp_config.data[i];
    switch (e._id) {
      case 'SecretId': r.SecretId = e.value; break;
      case 'SecretKey': r.SecretKey = e.value; break;
      case 'ProductId': r.ProductId = e.value; break;
    }
  }
  return r
}


function LedTextParams2Json(text: string, speed: number, count: number) {
  return JSON.stringify({
    // 数据转换
    text: ((t) => {
      // 转GB2312
      let encoded = iconv.encode(t, 'gbk');
      // 转BASE64
      return encoded.toString('base64')
    })(text),
    // 数据过滤
    speed: ((s) => {
      let t = parseInt(`${s}`)
      return t > 50 ? 50 : t < 20 ? 20 : t
    })(speed),
    // 数据过滤
    count: ((s) => {
      let t = parseInt(`${s}`)
      return t > 99999 ? 99999 : t < 0 ? 0 : t
    })(count)
  })
}


function onGbkBase64toUtf8(text: string) {

  return iconv.decode(Buffer.from(text, 'base64'), 'gbk')
}